﻿using GomokuCore;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace GomokuAI
{
    public static class Evaluator
    {
        public static int Evaluate(PositionStatus[,] board)
        {
            int score = 0;

            // Left ~ Right
            score += Evaluate(board, new Position(0, 0), pos => pos.Offset(1, 0), pos => pos.Offset(0, 1));
            // Top ~ Bottom
            score += Evaluate(board, new Position(0, 0), pos => pos.Offset(0, 1), pos => pos.Offset(1, 0));
            // BottomLeft ~ TopRight
            score += Evaluate(board, new Position(Game.BoardSize - 1, 0), pos => pos.Row > 0 ? pos.Offset(-1, 0) : pos.Offset(0, 1), pos => pos.Offset(1, 1));
            // TopLeft ~ BottomRight
            score += Evaluate(board, new Position(0, 0), pos => pos.Row < Game.BoardSize - 1 ? pos.Offset(1, 0) : pos.Offset(0, 1), pos => pos.Offset(-1, 1));

            return score;
        }

        private static int Evaluate(PositionStatus[,] board, Position startPos, Func<Position, Position> nextRow, Func<Position, Position> nextCol)
        {
            int score = 0;

            Position rowStart = startPos;
            while (true)
            {
                var last = PositionStatus.Invalid;
                int open = 0;
                int count = 0;

                Position pos = rowStart;
                while (true)
                {
                    if (board[pos.Row, pos.Col] == PositionStatus.Empty)
                    {
                        open = count == 0 ? 1 : open + 1;
                    }

                    if (last != board[pos.Row, pos.Col] && count > 0 && open > 0)
                    {
                        int sign = last == PositionStatus.Black ? 1 : -1;

                        if (count >= 5)
                            score += sign * 100000;
                        else if (count == 4 && open == 2)
                            score += sign * 10000;
                        else if (count == 4 && open == 1)
                            score += sign * 1000;
                        else if (count == 3 && open == 2)
                            score += sign * 1000;
                        else if (count == 3 && open == 1)
                            score += sign * 100;
                        else if (count == 2 && open == 2)
                            score += sign * 100;
                        else if (count == 2 && open == 1)
                            score += sign * 50;
                        else if (count == 1 && open == 2)
                            score += sign * 10;
                        else if (count == 1 && open == 1)
                            score += sign * 5;

                        open = board[pos.Row, pos.Col] == PositionStatus.Empty ? 1 : 0;
                        count = 0;
                    }

                    if (board[pos.Row, pos.Col] == PositionStatus.Black || board[pos.Row, pos.Col] == PositionStatus.White)
                    {
                        if (last == board[pos.Row, pos.Col])
                        {
                            count++;
                        }
                        else
                        {
                            count = 1;
                        }
                    }

                    last = board[pos.Row, pos.Col];

                    pos = nextCol(pos);

                    if (pos == Position.Null)
                        break;
                }

                rowStart = nextRow(rowStart);

                if (rowStart == Position.Null)
                    break;
            }

            return score;
        }
    }
}
